package com.undsf.despot;

import com.undsf.despot.modles.*;
import com.undsf.utility.Node;
import com.undsf.utility.Random;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Created by Arathi on 2016/10/3.
 */
public class CombatContext {
    protected List<Force> forces;
    protected List<Command> commands;
    protected CombatLog combatLog;

    public static CombatContext CreateCombatContext() {
        CombatContext instance = new CombatContext();
        return instance;
    }

    public CombatContext() {
        init();
    }

    @Deprecated
    public CombatContext(Metadata metadata) {
        init(metadata);
    }

    @Deprecated
    public void init(Metadata metadata) {
        // this.metadata = metadata;
        // monsterFactory = new _MonsterFactory(metadata);
        // buffFactory = new _BuffFactory(metadata);
        combatLog = new CombatLog();
        forces = new ArrayList<Force>();
    }

    public void init() {
        combatLog = new CombatLog();
        forces = new ArrayList<Force>();
    }

    public void putForces(int idA, int idB) {
        Monster monA = Metadata.GetCommonMetadata().createMonster(idA);  // monsterFactory.create(idA);
        Monster monB = Metadata.GetCommonMetadata().createMonster(idB);  // monsterFactory.create(idB);
        putForces(monA, monB);
    }

    public void putForces(Unit unitA, Unit unitB) {
        Team teamA = new Team();
        teamA.add(unitA);
        Force forceA = new Force();
        forceA.add(teamA);

        Team teamB = new Team();
        teamB.add(unitB);
        Force forceB = new Force();
        forceB.add(teamB);

        putForces(forceA, forceB);
    }

    public void putForces(Force fa, Force fb) {
        fa.setEnemies(fb);
        fb.setEnemies(fa);
        forces.add(fa);
        forces.add(fb);
    }

    public void selectCommands() {
        commands = new ArrayList<Command>();
        for (Force force : forces) {
            commands.addAll(force.selectCommands());
        }
    }

    public void executeCommands() {
        // 命令按照单位的敏捷排序
        Collections.sort(commands);
        for (Command command : commands) {
            // 检查单位状态
            Unit src = command.getSrc();
            if (src.getHp() <= 0) {
                // 单位已经死亡，跳过
                return;
            }
            switch (command.getInstruct()) {
                case Command.INSTRUCT_ATTACK:
                    executeAttack(command);
                    break;
                case Command.INSTRUCT_DEFENSE:
                    executeDefense(command);
                    break;
                case Command.INSTRUCT_CAST:
                    executeCast(command);
                    break;
                case Command.INSTRUCT_ITEM:
                    executeItem(command);
                    break;
                case Command.INSTRUCT_RUN:
                    executeRun(command);
                    break;
                case Command.INSTRUCT_WAIT:
                    executeWait(command);
                    break;
                default:
                    combatLog.addLine("[无法处理的命令] " + command.toString());
            }
        }
    }

    public void executeAttack(Command cmd) {
        Unit src = cmd.getSrc();
        // 攻击指令只会有一个目标
        Unit target = cmd.getTargets().get(0);
        combatLog.addLine(cmd.toString());
        int damageBase = src.getAttack() - target.getDefense()/2;
        int damage = (int)(damageBase * Random.GetRandomizer().nextDouble(0.45,0.55));
        if (damage<0) damage = 0;
        int delta = target.changeHp(-damage);
        if (delta >= 0) {
            combatLog.addLine("但是攻击失败，" + target.getName() + "毫发无损");
        }
        else {
            combatLog.addLine("对" + target.getName() + "造成" + -delta + "点伤害");
        }
    }

    public void executeDefense(Command cmd) {
        Unit src = cmd.getSrc();
        combatLog.addLine(src.getName()+"正在防御");
    }

    public void executeCast(Command cmd) {
        Unit src = cmd.getSrc();
        combatLog.addLine(cmd.toString());
        Skill skill = cmd.getSkill();

        // 检查是否沉默
        boolean silented = src.checkBuff("silent");
        if (silented) {
            combatLog.addLine("但是" + src.getName() + "的咒文被封住了");
            return;
        }

        // 检查是否有足够的MP
        if (src.getMp() - skill.getCostMp() < 0) {
            combatLog.addLine("但是MP不足");
            return;
        }
        // 扣除MP
        src.changeMp(-skill.getCostMp());

        // TODO 检查是否有目标
        for (Unit target : cmd.getTargets()) {
            // TODO 检查目标单位抗性
            boolean failure = false;
            String property = skill.getProperty();
            int resist = target.getResistance(property);
            if (resist == 7) {
                failure = true;
            }
            else if (resist == 0) {
                failure = false;
            }
            else {
                int r = Random.GetRandomizer().nextInt(0, 8);
                failure = r<resist;
            }
            // 根据技能的效果做相应的处理
            if (skill.isDamageSkill()) {
                // TODO 检查目标单位是否可攻击
                // 伤害效果
                int delta = 0;
                if (!failure) {
                    int damage = Random.GetRandomizer().nextInt(skill.getDamageMin(), skill.getDamageMax() + 1);
                    // TODO 检查伤害类型，检查目标单位技能，修正伤害值
                    if (damage < 0) damage = 0;
                    delta = target.changeHp(-damage);
                }
                if (delta == 0) {
                    combatLog.addLine("对" + target.getName() + "毫无作用");
                }
                else {
                    combatLog.addLine("对" + target.getName() + "造成" + -delta + "点伤害");
                }
            }
            if (skill.isHealSkill()) {
                // 治疗效果
                int heal = Random.GetRandomizer().nextInt(skill.getHealMin(), skill.getHealMax()+1);
                // TODO 检查是否有阻止生命恢复的debuff
                if (heal<0) heal = 0;
                int delta = target.changeHp(heal);

                if (delta == 0) {
                    combatLog.addLine("但是没有效果");
                }
                else {
                    combatLog.addLine(target.getName() + "恢复" + delta + "点生命");
                }
            }
            if (skill.isBuffSkill()) {
                if (!failure) {
                    // 添加buff
                    Identify64 buffId = skill.getBuff();
                    Buff buff = Metadata.GetCommonMetadata().createBuff(buffId.code);
                    // TODO 检查是否已经有同种buff
                    // 设置buff
                    target.putBuff(buff);
                    if (buff.getEffectiveDescription() != null) {
                        combatLog.addLine(target.getName() + buff.getEffectiveDescription());
                    }
                }
                else {
                    combatLog.addLine("对" + target.getName() + "毫无作用");
                }
            }
        }
    }

    public void executeItem(Command cmd) {
        //
    }

    public void executeRun(Command cmd) {
        // TODO 目前100%被包围，实际运算要根据状态和敏捷
        Unit src = cmd.getSrc();
        combatLog.addLine(src.getName() + "逃跑了……");
        combatLog.addLine("但是被包围了");
    }

    public void executeWait(Command cmd) {
        Unit src = cmd.getSrc();
        if (src.checkBuff("sleep")) {
            Buff sleepDebuff = src.getBuff("sleep");
            if (sleepDebuff.getTimeLeft() > 0) {
                combatLog.addLine(src.getName() + "睡着了");
            }
            else {
                src.removeBuff("sleep");
                combatLog.addLine(src.getName() + "醒来了");
            }
        }
        else {
            // combatLog.addLine(src.getName() + "什么也没做");
            combatLog.addLine(src.getName() + "正在发呆");
        }
    }

    public boolean hasNextTurn() {
        for (Force force : forces) {
            if (!force.isFightable()) return false;
        }
        return true;
    }

    public void statusReport() {

    }
}
